package com.s.core.root.strategy;

import com.s.core.root.Ad;
import com.s.core.root.CodeFeature;
import com.s.core.root.D;
import com.s.core.root.data._AllData;
import com.s.core.root.strategy.factor.MaxVol;
import com.s.core.root.strategy.factor.Yd;
import com.s.core.root.strategy.factor.ZtActivity;
import com.s.core.root.strategy.factor.pics.*;
import com.s.core.root.strategy.factor.pics.combination.F_Pics_Activity;
import com.s.core.root.strategy.factor.pics.combination.F_Pics_ActivityPair;
import com.s.core.root.strategy.factor.pics.combination.F_Pics_LastStrong;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class Strategy {
    public static final int TOP_ZT_LIMIT = 3;
    public static int ACTIVE_ZT_LIMIT = 100;
    public static int ACTIVE_ZT_SUPER_LIMIT = 240;

    public enum STRATEGY {
        MAX_VOL,
        MORE_ACTIVE,
        ACTIVE_ZT,
        SUPER_ACTIVE_ZT,
        ZT_MORE,
        ;

        public static Strategy.STRATEGY byString(String s) {
            return Arrays.stream(values()).
                    filter(strategy -> strategy.toString().equals(s)).findFirst().orElse(null);
        }
    }

    @AllArgsConstructor
    @Data
    public static class StrategyCode {
        private String code;
        private STRATEGY strategy;
    }

    private static volatile Strategy me;

    public static Strategy me() {
        if (me == null) {
            synchronized (Strategy.class) {
                if (me == null) {
                    me = new Strategy();
                }
            }
        }
        return me;
    }

    public StrategyCode get(String code, String date) {
        //base start
        if (!CodeFeature.isCanBuy(code)) {
            return null;
        }
        D d = Ad.me().getDaily(date, code);
        if (d == null) {
            return null;
        }
        int ztActivity = ZtActivity.calculate(d);
        if (!Yd.isYd(d, ztActivity >= ACTIVE_ZT_SUPER_LIMIT)) {
            return null;
        }
        _AllData allData = new _AllData(d);
        if (!allData.containFeature(F_Pics_LastStrong.class)) {
            return null;
        }
        //base done
        if (allData.containFeature(F_Pics_LastBigMaxStrong.class) &&
                allData.getFeature(F_Pics_LastBigMaxStrong.class).getPosN() <= 10) {
            return new StrategyCode(allData.d.code, STRATEGY.MAX_VOL);
        }
        if (MaxVol.isMaxVol(d, new int[]{0, 1}, 100) && d.ztCounts(5, true) >= 2) {
            return new StrategyCode(allData.d.code, STRATEGY.MAX_VOL);
        }
        if (allData.containFeature(F_Pics_Activity.class) &&
                allData.getFeature(F_Pics_Activity.class).size(null) >= (ztActivity >= ACTIVE_ZT_SUPER_LIMIT ? 5 : 8)) {
            return new StrategyCode(allData.d.code, STRATEGY.MORE_ACTIVE);
        }
        if (ztActivity >= ACTIVE_ZT_SUPER_LIMIT &&
                d.isContainsSy(2, new float[]{0.9f, 0.8f, 0.7f, 0.6f, 0.5f})) {
            return new StrategyCode(allData.d.code, STRATEGY.SUPER_ACTIVE_ZT);
        }
        if (d.ztCounts(15, true) >= 3) {
            return new StrategyCode(allData.d.code, STRATEGY.ZT_MORE);
        }
        if (allData.containFeature(F_Pics_ActivityPair.class) &&
                allData.getFeature(F_Pics_ActivityPair.class).size(10) > 0 &&
                ztActivity >= ACTIVE_ZT_LIMIT) {
            D b1 = allData.d.bDaily(1);
            D b2 = allData.d.bDaily(2);
            _AllData allData1 = b1 == null ? null : new _AllData(b1);
            _AllData allData2 = b2 == null ? null : new _AllData(b2);
            boolean isPreActive = allData1 != null && allData1.containFeature(F_Pics_ActivityPair.class) && allData1.getFeature(F_Pics_ActivityPair.class).size(10) > 0 ||
                    allData2 != null && allData2.containFeature(F_Pics_ActivityPair.class) && allData2.getFeature(F_Pics_ActivityPair.class).size(10) > 0;
            if (isPreActive) {
                return new StrategyCode(allData.d.code, STRATEGY.ACTIVE_ZT);
            }
        }
        return null;
    }

    public List<StrategyCode> get(List<String> codes, String date) {
        return codes.stream()
                .map(c -> get(c, date))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }

    public String topZt(String date, List<String> allStrategyCodes) {
        Map<Integer, List<String>> sortedMap = new TreeMap<>(Comparator.reverseOrder());
        List<D> dList = Ad.me().getCodes().stream().
                filter(CodeFeature::isCanBuy).
                map(code -> Ad.me().getDaily(date, code)).
                filter(Objects::nonNull).
                collect(Collectors.toList());
        for (D d : dList) {
            int ztLastCount = d.ztLastCounts();
            int ztLastCount1 = 0;
            int ztLastCount2 = 0;
            D bd1 = d.bDaily(1);
            if (bd1 != null) {
                ztLastCount1 = bd1.ztLastCounts();
            }
            D bd2 = d.bDaily(2);
            if (bd2 != null) {
                ztLastCount2 = bd2.ztLastCounts();
            }
            int finalZtLastCount = Math.max(ztLastCount, Math.max(ztLastCount1, ztLastCount2));
            if (finalZtLastCount < TOP_ZT_LIMIT) {
                continue;
            }
            if (!sortedMap.containsKey(finalZtLastCount)) {
                sortedMap.put(finalZtLastCount, new ArrayList<>());
            }
            if (allStrategyCodes.contains(d.code)) {
                sortedMap.get(finalZtLastCount).add(d.code);
            } else {
                sortedMap.get(finalZtLastCount).add("(" + d.code + ")");
            }
        }
        StringBuilder result = new StringBuilder();
        for (Map.Entry<Integer, List<String>> entry : sortedMap.entrySet()) {
            result.append(entry.getKey()).append(":").append(entry.getValue()).append("\n");
        }
        return result.toString();
    }
}
